這章開始,我們要探索另一個 JS 裡的重大謎團──總是讓人搞不清楚是這個還是那個的 this
。
this
?在介紹 this
之前,首先來看看 this
的出現究竟想解決什麼問題。
const person1 = {
name: 'Amy'
}
const person2 = {
name: 'Jack'
}
function speak(context) {
console.log(`Hello, I'm ${context.name}`)
}
speak(person1); // Hello, I'm Amy
speak(person2); // Hello, I'm Jack
在上面的程式碼中,如果要取得物件中的 name
,必須在調用函式時將物件作為參數傳入。
但當整個模式與架構變得複雜時,像這樣將執行環境以參數傳遞的方式會變得難以識讀,而 this
的功能,就是帶來更優雅乾淨的 API 設計。
this
?關於 this
,根據 ECMAScript 的定義,this
的值指向「當前執行環境的 this
綁定」,這是什麼意思呢?
讓我們用 this
改寫上面的程式碼試試:
const person1 = {
name: 'Amy',
speak,
}
const person2 = {
name: 'Jack',
speak,
}
function speak() {
console.log(`Hello, I'm ${this.name}`)
}
person1.speak(); // Hello, I'm Amy
person2.speak(); // Hello, I'm Jack
回顧一下這段神奇的程式碼,在調用 speak()
的時候並沒有傳入任何參數,teacher
和 student
的名字卻可以順利被打印出來。
this
是什麼神奇的魔法,為什麼能夠找到這兩個人的名字?
回顧 speak
這個函式的調用過程,我們從結果往回推論,不難導出 teacher.speak()
和 student.speak()
的 this
分別指向了 teacher
和 student
這兩個物件。
也就是說,當 teacher
內部的 speak
被調用時,this
指向了 teacher
物件,而調用 student
的 speak
時,函式內的 this
就指向了 student
物件。
當調用的外部環境改變, this
所指的對象也跟著改變。
接著再來看看,如果 speak
被單獨調用會發生什麼?
speak(); // Hello, I'm undefined
此時 this.name
回傳的值變成了 undefined
。
這裡把函式稍微調整一下,用更直接的方式看看 this
的真面目:
function callThis() {
console.log(this)
}
const person1 = {
name: 'Amy',
callThis,
}
const person2 = {
name: 'Jack',
callThis,
}
person1.callThis();
// { name: 'Amy', callThis: [Function: callThis] }
person2.callThis();
// { name: 'Jack', callThis: [Function: callThis] }
callThis();
// Window
在最後一個單獨調用的 callThis
,我們發現它的 this
指向了 Window
,也就是全域物件(在 Node.js 內就會是 global
物件),因為全域變數就是全域物件的屬性,所以函式去尋找 Window
底下的 name
這個變數但一無所獲,於是最後回傳了 undefined
。
this
的特徵初步了解 this
之後,以下總結它的幾個特徵:
this
不是this
指向的不是包覆它的函式。this
指向的不是包覆它的函式的作用域,也無法進行詞法作用域查找this
與包覆它的函式如何宣告無關this
是this
是一個 JS 的保留字/關鍵字this
在函式執行時產生this
隨著函式的調用方式不同而改變this
指向一個物件,該物件在函式被調用時綁定在 this
上this
指向調用這個函式的物件(或者說調用時該函式所屬的物件)下一章,我們接著來看看 JS 中,那些能夠指定 this
綁定對象的方法。